﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using EzDesk.Core.Model;
using System.Web;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;

namespace EzDesk.Core.CoreImpl.Services.AppPortal
{
    public abstract class CallbackContentBuilder
    {
        public static CallbackContentBuilder CreateBuilder(string httpMethod, IAppSessionService appSessionService)
        {
            CallbackContentBuilder builder = null;
            if (httpMethod.ToUpper() == "GET")
            {
                builder = new GetCallbackContentBuilder();
            }
            if (httpMethod.ToUpper() == "POST")
            {
                builder = new PostCallbackContentBuilder();
            }

            if (builder == null)
            {
                throw new Exception("http method NOT supported!!");
            }

            builder._appSessionService = appSessionService;
            return builder;
            
        }

        protected string appName;
        protected string targetUrl;
        protected Guid userId;
        protected NameValueCollection formCollection;
        protected AppSession currentSession;
        protected IAppSessionService _appSessionService;

        public HttpContent GetReqest(string appName, string targetUrl, Guid userId, NameValueCollection formCollection)
        {
            this.appName = appName;
            this.targetUrl = targetUrl;
            this.userId = userId;
            this.formCollection = formCollection;

            HttpContent finalContent = null;

            finalContent = processRequest();
            return finalContent;
        }

        private HttpContent processRequest()
        {
            // 取得目标Url
            string targetUrl = generateRealUrl();

            // 生成PostData
            byte[] postData = generatePostData();

            // 向目标发送请求,获得返回响应
            WebResponse respone = getResponse(targetUrl, postData);

            string content = getContentFromWebResponse(respone);
            string contentType = respone.ContentType;

            // 对响应做二次处理
            string finalContentStr = processContent(content, respone.ContentType);

            return new HttpContent()
            {
                Content = finalContentStr,
                ContentType = contentType,
            };
        }
        
        protected virtual byte[] generatePostData()
        {
            byte[] bytes = null;
            if (formCollection != null)
            {
                bytes = Encoding.UTF8.GetBytes(getPostString(formCollection));
            }
            return bytes;
        }

        private string getPostString(NameValueCollection formCollection)
        {
            StringBuilder postSb = new StringBuilder();
            foreach (string key in formCollection.AllKeys)
            {
                string[] valueItems = formCollection[key].Split(',');
                foreach (var item in valueItems)
                {
                    postSb.AppendFormat("{0}={1}&", key, item);
                }                
            }
            return postSb.ToString();
        }

        protected virtual string processContent(string content, string contentType)
        {
            StringBuilder contentTextBuilder = new StringBuilder(content);

            //todo: 对HTML内容进行渲染
            
            //// 只有在HTML情况下，进行二次渲染
            //if (contentType.Contains("text/html"))
            //{
            //    string sessionString = makeSessionTags(currentSession);


            //    Regex regex = new Regex("<(form)\\s*[^<>]*>", RegexOptions.IgnoreCase);
            //    MatchCollection matches = regex.Matches(content);

            //    int formIndex, occurTimes = 0;
            //    foreach (Match match in matches)
            //    {
            //        formIndex = match.Index + match.Length + occurTimes * sessionString.Length;
            //        contentTextBuilder.Insert(formIndex, sessionString);
            //        occurTimes++;
            //    }
            //}
            return contentTextBuilder.ToString(); 
        }

        protected virtual string generateRealUrl()
        {
            // 获得当前Session
            currentSession = _appSessionService.GetAppSession(userId, appName);
            // 将Session加入Url
            string realUrl = generateTargetUrl(targetUrl, true);
            return realUrl;
        }

        protected abstract WebResponse getResponse(string targetUrl, byte[] encodedPostData);
        
        protected string generateTargetUrl(string targetFuncUrl, bool includeSessionInQuery = true)
        {
            StringBuilder sb = new StringBuilder(targetUrl);

            if (includeSessionInQuery)
            {
                string sessionQuery = makeQueryWithAppSession(currentSession);
                if (targetFuncUrl.Contains("?"))
                {
                    sb.Append(string.Format("&{0}", sessionQuery));
                }
                else
                {
                    sb.Append(string.Format("?{0}", sessionQuery));
                }
            }

            return sb.ToString();
        }


        #region [ private methods ]
        private static string getContentFromWebResponse(WebResponse respone)
        {
            string content = string.Empty;
            var stream = respone.GetResponseStream();
            using (var sr = new StreamReader(stream))
            {
                content = sr.ReadToEnd();
            }
            return content;
        }

        private string makeSessionTags(AppSession currentSession)
        {
            string tagTemplate = "<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />";

            StringBuilder tagBuilder = new StringBuilder();
            tagBuilder.AppendFormat(tagTemplate, "ez_user", currentSession.UserId);

            return tagBuilder.ToString();
        }

        private string makeQueryWithAppSession(AppSession currentSession)
        {
            // 将Session加入Url
            NameValueCollection nameValueCol = new NameValueCollection();
            nameValueCol["ez_user"] = currentSession.UserId;

            var queryBuilder = new StringBuilder();

            for (int i = 0; i < nameValueCol.Count; i++)
            {
                queryBuilder.Append(
                    string.Format("{0}={1}", nameValueCol.Keys[i], HttpUtility.UrlEncode(nameValueCol[i]))
                    );
                if (i != nameValueCol.Count - 1)
                {
                    queryBuilder.Append("&");
                }
            }
            return queryBuilder.ToString();
        }
        #endregion

    }









    /// <summary>
    /// 处理GET转发请求的Builder
    /// </summary>
    public class GetCallbackContentBuilder : CallbackContentBuilder
    {
        protected override WebResponse getResponse(string targetUrl, byte[] encodedPostData = null)
        {
            // get方法返回
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(targetUrl);
            request.CookieContainer = new CookieContainer();
            return request.GetResponse();
        }
    }




    /// <summary>
    /// 处理POST转发请求的Builder
    /// </summary>
    public class PostCallbackContentBuilder : CallbackContentBuilder
    {
        protected override WebResponse getResponse(string targetUrl, byte[] postData)
        {
            // post发送数据
            var request = (HttpWebRequest)WebRequest.Create(targetUrl);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = postData.Length;
            request.CookieContainer = new CookieContainer();

            using (var requestStream = request.GetRequestStream())
            {
                requestStream.Write(postData, 0, postData.Length);
            }

            return request.GetResponse();
        }
    }

}
